/**
 * 
 */
package com.secfound.soccer.client.gui;


import java.util.List;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.secfound.soccer.client.BettingServiceAsync;
import com.secfound.soccer.client.LoginServiceAsync;
import com.secfound.soccer.client.tools.Flagman;
import com.secfound.soccer.client.tools.PageExtractor;
import com.secfound.soccer.shared.db.Bet;
import com.secfound.soccer.shared.db.Challenger;
import com.secfound.soccer.shared.db.Game;
import com.secfound.soccer.shared.db.Team;

/**
 * GUI for the application
 * @author alfonso.ayala
 *
 */
public class ScoreboardGUI {
	/* Constants. */
	private static final String UPPERLINE = "upperline";
	private static final String CHALLENGER_PANEL = "boxchallenger";
	private static final String MAIN_PANEL = "mainpanel";
	private static final String TABLE_PANEL = "listpanel";
	private static final String GRID_STYLE = "marty";
	private static final int PAGELENGHT = 10;

	/* GUI Widgets */
	private BettingServiceAsync bookingService=null;
	private LoginServiceAsync loginService=null;
	private Label aTeam;
	private Label bTeam;
	private HTML worldcup ;
	private ListBox listAScore;
	private ListBox listBScore;
	private Label labelStarttime;
	private DialogBox betBox;
	private Button betCloseButton ;
	private Button betSendButton;
	private Button betNextButton;
	protected Label errorLabel = new Label();
	private HTML serverResponseLabel;
	private HTML serverResponseTitle;

	private ListBox listOptions;
	private ListBox pageSelection;
	private HTML linkBar;
	private HTML challengerInfo;
	private HTML htmlAteam;
	private HTML htmlBteam;
	private HorizontalPanel dashboardPanel;
	private Challenger challenger;
	private VerticalPanel vp;
	private Grid grid =null;
	
	/* variables */
	protected List<Game> fullGameList;
	protected List<Bet>  fullBetList;
	protected List<Team> fullTeamList;
	protected int maxtries=3;
	protected int currenttry=0;
	protected int currentQuestion=0;

	public void init(BettingServiceAsync bookingService, LoginServiceAsync authService, Challenger gamer) {    
		this.bookingService=bookingService;
		this.loginService=authService;
		if(gamer !=null){
			this.challenger = gamer;
		}else{
			this.challenger= new Challenger();
			this.challenger.setLoggedIn(false);	
		}
		buildDashboard();
		loadTeamList();
	}

	private void loadTeamList(){
		Team team = new Team();
		bookingService.listTeams(team, new AsyncCallback<List<Team>>(){
			@Override
			public void onFailure(final Throwable caught) {
				final String msg= "Remote Procedure Call - Failure\n"+
						caught.getMessage() ;
				Window.alert( msg );
			}
			@Override
			public void onSuccess(final List<Team> result) {
				fullTeamList = result;
			}});
	}

	private void hideDashboard() {
		dashboardPanel.setVisible( false);	
	}

	private void buildDashboard() {
		dashboardPanel = new HorizontalPanel();
		pageSelection = new ListBox();
		pageSelection.addChangeHandler(new PageChangeHandler() );
		pageSelection.setVisible(false);
		listOptions = new ListBox();
		listOptions.addItem("Please select one:");
		listOptions.addItem("Future Games");
		listOptions.addItem("Past Games");
		listOptions.addItem("Bets");
		listOptions.addChangeHandler( new OptionChangeHandler() );
		dashboardPanel.add(listOptions);
		dashboardPanel.add(pageSelection);
		RootPanel.get(MAIN_PANEL).add( dashboardPanel );
		
		linkBar = new HTML();
		challengerInfo= new HTML("Empty");
		if(challenger.isLoggedIn() ){
			linkBar.setHTML( challenger.getNickname() + " <a href='"+ challenger.getLogoutURL() +"'>Sign Out</a>");
			showChallenger(challenger);
		}else{
			linkBar.setHTML( " <a href='"+ challenger.getLoginURL() +"'>Sign In</a>"  );
		}
		RootPanel.get(CHALLENGER_PANEL).add( challengerInfo );	
		RootPanel.get(UPPERLINE).add( linkBar );
	}

	public void showChallenger(final Challenger chall){
		if(chall!=null && challengerInfo!=null){
			challengerInfo.setHTML( 
					"<b>Nickname:</b> "        + chall.getNickname()     + 
					" | <b>Points:</b> "       + chall.getPoints()       + 
					" | <b>Training Hits:</b> "+ chall.getTrainingHits() + " / "+ chall.getTrainingTries()+
					" | <b>Hits:</b> "         + chall.getHits()         + " / "+ chall.getTries() 
					);
		}
	}

	public void refreshBetDialog(String aTeamName, String bTeamName, String challenger, String startTime, String city, String stage ){
		worldcup.setHTML("<b>Cup:</b> "+ startTime.substring(0,4)+ " <b>Stage:</b> "+ stage+" <b>Date:</b> "+ startTime.substring(0,10));
		aTeam.setText(aTeamName);
		bTeam.setText(bTeamName);
		htmlAteam.setHTML( Flagman.getHTML( getTeamByName( aTeamName ) ) );
		htmlBteam.setHTML( Flagman.getHTML( getTeamByName( bTeamName ) ) );
	}

	private void createBetDialog(String aTeamName, String bTeamName, String challenger, String startTime, String city, String stage ) {
		currenttry=0;
		betBox=	 new DialogBox();

		betSendButton = new Button("Send");
		betNextButton = new Button(">");
		betNextButton.setVisible(false);
		serverResponseTitle = new HTML("&nbsp;");
		serverResponseLabel = new HTML("&nbsp;");
		labelStarttime      = new Label(startTime);
		htmlAteam           = new HTML("&nbsp;");
		htmlBteam           = new HTML("&nbsp;");

		betBox.setText("Estimating");
		betBox.setAnimationEnabled(true);
		betCloseButton = new Button("Close");
		betCloseButton.getElement().setId("betCloseButton");

		VerticalPanel dialogVPanel = new VerticalPanel();
		dialogVPanel.addStyleName("dialogVPanel");
		dialogVPanel.add(new HTML("<b>Your Score:</b>"));
		listAScore = new ListBox();
		listBScore = new ListBox();
		for(int i=0;i<11;i++){
			listAScore.addItem( Integer.toString( i ) );
			listBScore.addItem( Integer.toString( i ) );	
		}		
		HorizontalPanel line0 = new HorizontalPanel();
		worldcup = new HTML("<b>Cup:</b> "+ startTime.substring(0,4)+ " <b>Stage:</b> "+ stage+" <b>Date:</b> "+ startTime.substring(0,10));
		line0.add(worldcup);

		HorizontalPanel line1 = new HorizontalPanel();
		aTeam = new Label(aTeamName);
		htmlAteam.setHTML( Flagman.getHTML( getTeamByName( aTeamName ) ) );
		line1.add(htmlAteam);
		line1.add(listAScore);

		bTeam = new Label(bTeamName);
		htmlBteam.setHTML(Flagman.getHTML( getTeamByName( bTeamName )) );
		line1.add(htmlBteam);
		line1.add(listBScore);

		HorizontalPanel line2 = new HorizontalPanel();
		line2.add(betSendButton);
		line2.add(betNextButton);
		line2.add(betCloseButton);
	
		line2.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);

		dialogVPanel.add(line0);
		dialogVPanel.add(line1);

		dialogVPanel.add(serverResponseTitle);
		dialogVPanel.add(serverResponseLabel);
		dialogVPanel.add(line2);

		dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);

		betBox.setWidget(dialogVPanel);
		betCloseButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				betBox.hide();
				betCloseButton.setEnabled(true);
				betSendButton.setFocus(true);
			}
		});	
		betSendButton.addClickHandler(new SendBetHandler());
		betNextButton.addClickHandler(new SendNextHandler());
	}

	private void buildGridOfGames(List<Game> result, int page ){
		RootPanel.get( TABLE_PANEL ).clear();
		vp = new VerticalPanel();
		vp.setSpacing(10);
		int row=0;
		if(result!=null && result.size()>0){		
			grid = new Grid(result.size()+1, 8);
			grid.setText(row,0,"Cup");
			grid.setText(row,1,"Stage");
			grid.setText(row,2,"City");
			grid.setText(row,3,"Team A");
			grid.setText(row,4,"Team B");
			grid.setText(row,5,"");
			grid.setText(row,6,"Action");
			row++;
			for(final Game g: result){
				grid.setText(row,0,g.getStartTime().substring(0,4));
				grid.setText(row,1,g.getStage());
				grid.setText(row,2,g.getCity());
				grid.setWidget(row, 3, new HTML( Flagman.getHTML( getTeamByName( g.getaTeam() ) )    ));
				grid.setWidget(row, 4, new HTML( Flagman.getHTML( getTeamByName( g.getbTeam() ) )    ));
				
				Button rowButton = new Button("Bet");
				rowButton.addClickHandler(new ClickHandler() {
					public void onClick(ClickEvent event) {
						createBetDialog(g.getaTeam(), 
								g.getbTeam(), 
								challenger.getEmail(), 
								g.getStartTime(), 
								g.getCity(), 
								g.getStage());
						betBox.center();
					}
				});
				grid.setWidget(row, 6, rowButton);
				row++;
			}
			grid.setStyleName(GRID_STYLE);
			vp.add(grid);
		}
		RootPanel.get(TABLE_PANEL).add( vp );
	}

	private Team getTeamByName(String getaTeam) {
		return searchIn(fullTeamList, getaTeam);
	}

	class LogoutHandler implements ClickHandler {
		@Override
		public void onClick(ClickEvent event) {
			loginService.logout("", new AsyncCallback<String>(){
				@Override
				public void onFailure(Throwable caught) {
					Window.alert("Logging OUT!!!");
					hideDashboard();
				}
				@Override
				public void onSuccess(String result) {
					Window.alert("Logged out");
				}});	
		}
	}

	public void fillPageSelection(List result){
		if(pageSelection!=null){
			pageSelection.clear();
			int pageNumber= result.size()/ PAGELENGHT;
			if(pageNumber<1){
				pageSelection.setVisible(false);
			}else{
				pageSelection.setVisible(true);
			}
			for(int i=0; i< pageNumber ; i++){
				pageSelection.addItem( "Page "+ Integer.toString(  (i+1) ) );
			}
		}
	}

	class OptionChangeHandler implements ChangeHandler{
		@Override
		public void onChange(ChangeEvent event) {
			sendQueryToServer();
		}
	}

	class PageChangeHandler implements ChangeHandler
	{
		@Override
		public void onChange(ChangeEvent event) {
			int selectedIndex = pageSelection.getSelectedIndex();
			if (selectedIndex >= 0){
				String strPage = pageSelection.getItemText(  selectedIndex  );
				int page = Integer.parseInt(  strPage.replace("Page ", "") );
				String option = listOptions.getItemText( listOptions.getSelectedIndex()  );
				if("Bets".equals(option)){
					if(fullBetList!=null){
						List<Bet> pageRows = PageExtractor.extractBetPage(fullBetList, page, PAGELENGHT );
						buildGridOfBets(pageRows );
					}
				}else{
					if(fullGameList != null){
						List<Game> pageRows = PageExtractor.extractGamePage(fullGameList, page, PAGELENGHT );
						buildGridOfGames(pageRows,page );
					}
				}
			}	
		}
	}

	class SendBetHandler implements ClickHandler {
		public void onClick(ClickEvent event) {
			sendBetToServer();
		}
		private void sendBetToServer() {
			currenttry++;
			errorLabel.setText("");
			Bet bet = new Bet( challenger.getEmail() 
					,aTeam.getText()
					,listAScore.getItemText( listAScore.getSelectedIndex() ) 
					,bTeam.getText()
					,listBScore.getItemText( listBScore.getSelectedIndex() )
					,labelStarttime.getText(), null
					);
			betSendButton.setEnabled(false);
			bookingService.storeBet(bet, new AsyncCallback<Challenger>(){
				@Override
				public void onFailure(Throwable caught) {
					String msg="Remote Procedure Call - Failure \n"+
							caught.getMessage() ;
					Window.alert( msg);
				}
				@Override
				public void onSuccess(Challenger chall) {
					showChallenger(chall);
					if(chall!=null){
						if(chall.getMsg().startsWith("Congrats")){
							betNextButton.setVisible(true);
							serverResponseTitle.setHTML("<b>Correct!</b>");
							betSendButton.setEnabled(false);
							betNextButton.setEnabled(true);
						}else if(chall.getMsg().startsWith("Your"))  {
							betNextButton.setVisible(false);
							betSendButton.setEnabled(false);
							serverResponseTitle.setHTML("<b>Thanks!</b>");
						}else {
							betNextButton.setVisible(true);
							serverResponseTitle.setHTML("<b>Bummer! "+ currenttry +" of "+ maxtries +" </b>");
							if(currenttry<maxtries){
								betSendButton.setEnabled(true);
							}else{
								betSendButton.setEnabled(false);
								betNextButton.setEnabled(true);
							}
						}
						serverResponseLabel.setText(chall.getMsg() );
					}		
				}});
		}
	}

	public class SendNextHandler implements ClickHandler {
		@Override
		public void onClick(ClickEvent event) {
			if(fullGameList!=null){
				currentQuestion++;
				currenttry=0;
				if(currentQuestion < fullGameList.size()){
					serverResponseTitle.setHTML("<b>&nbsp;</b>");
					serverResponseLabel.setText("");
					betSendButton.setEnabled(true);
					betNextButton.setEnabled(false);
					Game g = fullGameList.get(currentQuestion);
					refreshBetDialog( g.getaTeam(), g.getbTeam(), challenger.getEmail(), g.getStartTime(), g.getCity(), g.getStage() );			
				}	
			}
		}
	}

	class ListGamesHandler implements ClickHandler {
		public void onClick(ClickEvent event) {
			sendQueryToServer();
		}
	}

	private void sendQueryToServer() {
		String option= 	listOptions.getItemText( listOptions.getSelectedIndex()  );
		boolean isPast=false;		
		String startTime="";
		errorLabel.setText("");			
		String stage="Final";
		Game queryGame = new Game("", "", "", "", startTime, stage, "","");
		queryGame.setPast(isPast);
		queryGame.setOption(option);
		Bet queryBet = new Bet();
		queryBet.setChallenger(challenger.getEmail());
		if("Bets".equals(option)){
			bookingService.listBets(queryBet,	new AsyncCallback<List<Bet>>() {
				public void onFailure(Throwable caught) {
					String msg="Remote Procedure Call - Failure\n"+caught.getMessage();
					Window.alert(msg);
				}
				@Override
				public void onSuccess(List<Bet> result) {
					fullBetList = result;
					fillPageSelection(fullBetList);
					int page=1;
					List<Bet> pageRows = PageExtractor.extractBetPage(fullBetList, page, PAGELENGHT );
					buildGridOfBets( pageRows);
				}
			});
		}else{
			bookingService.listGames(queryGame,	new AsyncCallback<List<Game>>() {
				public void onFailure(Throwable caught) {
					String msg="Remote Procedure Call - Failure\n"+
							caught.getMessage();
					Window.alert(msg);
				}
				@Override
				public void onSuccess(List<Game> result) {
					fullGameList =result;
					fillPageSelection(fullGameList);
					int page=1;
					List<Game> pageRows = PageExtractor.extractGamePage(fullGameList, page, PAGELENGHT );
					buildGridOfGames( pageRows, 0);
				}
			});
		}
	}

	private void buildGridOfBets(List<Bet> result) {
		RootPanel.get( TABLE_PANEL ).clear();
		vp = new VerticalPanel();
		vp.setSpacing(10);
		int row=0;
		if(result!=null && ! result.isEmpty() ){
			grid = new Grid(result.size()+1, 8);	
			grid.setText(row,0,"Creation");
			grid.setText(row,1,"Cup");
			grid.setText(row,2,"Team-A");
			grid.setText(row,3,"Score-A");
			grid.setText(row,4,"Team-B");
			grid.setText(row,5,"Score-B");
			grid.setText(row,6,"Status");
			grid.setText(row,7,"Result");		
			row++;
			for(final Bet g: result){
				grid.setText(row,   0, g.getCreatedTime());
				grid.setText(row,   1, g.getStartTime().substring(0,4));
				grid.setWidget(row, 2, new HTML( Flagman.getHTML( getTeamByName( g.getaTeam() ) )    ));
				grid.setText(row,   3, g.getaScore());
				grid.setWidget(row, 4, new HTML( Flagman.getHTML( getTeamByName( g.getbTeam() ) )    ));
				grid.setText(row,   5, g.getbScore());
				grid.setText(row,   6, g.getStatus());
				if("open".equals(g.getStatus())){
					grid.setText(row,   7, "--");
				}else{
					grid.setText(row,   7, g.isSuccess() ? "OK" : "FAIL");
				}
				row++;
			}
			grid.setStyleName(GRID_STYLE);
			vp.add(grid);
		}
		RootPanel.get(TABLE_PANEL).add( vp );
	}

	public void login(String divname, String url) {
		VerticalPanel localvp = new VerticalPanel();
		localvp.setSpacing(10);
		String htmlLink="<a href='" + url+"'>Login</a>";
		localvp.add(new HTML(htmlLink));
		RootPanel.get(divname).add( localvp );
	}

	public Team searchIn( List<Team> list, String searched ) { 
		Team result=null; 
		for( Team t : list ) { 	 
			if( searched.equals( t.getName()) ) { 
				result=t;
			}
		}
		return result;
	}
}